package main

import (
	"bytes"
	"encoding/json"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)

var log = shim.NewLogger("account")

type SmartContract struct {
}

type Account struct {
	BusinessId string `json:businessId`
	CustNm     string `json:"custNm"`
	CustAcNo   string `json:"custAcNo"`
	TransAmt   string `json:"transAmt"`
	TransDate  string `json:"transDate"`
	Ccy        string `json:ccy`
	InstCode   string `json:"instCode"`
	Desc       string `json:"desc"`

	encoded []byte
	err     error
}

func (s *SmartContract) Init(APIstub shim.ChaincodeStubInterface) pb.Response {
	return shim.Success(nil)
}

func (s *SmartContract) Invoke(APIstub shim.ChaincodeStubInterface) pb.Response {

	function, args := APIstub.GetFunctionAndParameters()
	log.Infof("调用智能合约！%s", function)
	if function == "query" {
		return s.query(APIstub, args)
	} else if function == "init" {
		return s.initAccount(APIstub)
	} else if function == "create" {
		return s.create(APIstub, args)
	} else if function == "list" {
		return s.list(APIstub)
	} else if function == "update" {
		return s.update(APIstub, args)
	} else if function == "history" {
		return s.history(APIstub, args)
	} else if function == "invoke" {
		return s.invoke(APIstub, args)
	} else if function == "check" {
		return s.check(APIstub, args)
	}

	return shim.Error("Invalid Smart Contract function name.")
}

func (s *SmartContract) query(APIstub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 1 {
		log.Errorf("Incorrect number of arguments. Expecting 1")
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	carAsBytes, _ := APIstub.GetState(args[0])
	return shim.Success(carAsBytes)
}

func (s *SmartContract) initAccount(APIstub shim.ChaincodeStubInterface) pb.Response {
	Accounts := []Account{
		Account{BusinessId: "B0000001", CustNm: "林建明", CustAcNo: "41", TransAmt: "100000", TransDate: "20180917090501", Ccy: "cny", InstCode: "ncc", Desc: "初始化数据"},
		Account{BusinessId: "B0000002", CustNm: "小萨", CustAcNo: "3", TransAmt: "100", TransDate: "20180917090605", Ccy: "cny", InstCode: "ncc", Desc: "初始化数据"},
	}

	i := 0
	for i < len(Accounts) {
		accountAsBytes, _ := json.Marshal(Accounts[i])
		APIstub.PutState(Accounts[i].BusinessId, accountAsBytes)
		log.Debugf("Added %s", Accounts[i])
		i = i + 1
	}

	return shim.Success(nil)
}

func (s *SmartContract) create(APIstub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 5 {
		log.Errorf("参数数量不正确，期望为5个")
		return shim.Error("Incorrect number of arguments. Expecting 5")
	}

	var account = Account{BusinessId: args[1], CustNm: args[2], CustAcNo: args[3], TransAmt: args[4], TransDate: args[5], Ccy: args[6], InstCode: args[7], Desc: args[8]}
	log.Debugf("New Added: %s", account)
	accountAsBytes, _ := json.Marshal(account)
	log.Debugf("New args[0]: %s", args[0])
	log.Debugf("New accountAsBytes:%s", accountAsBytes)
	APIstub.PutState(args[0], accountAsBytes)
	err := APIstub.SetEvent("create", accountAsBytes)
	if err != nil {
		log.Error("监听事件异常!", err)
	}
	log.Debugf("发送事件 %s", "create")

	return shim.Success(nil)
}

func (s *SmartContract) list(APIstub shim.ChaincodeStubInterface) pb.Response {

	startKey := "B0000001"
	endKey := "B9999999"

	resultsIterator, err := APIstub.GetStateByRange(startKey, endKey)
	if err != nil {
		log.Error("GetStateByRange 异常!", err.Error())
		return shim.Error(err.Error())
	}
	defer resultsIterator.Close()

	// buffer is a JSON array containing QueryResults
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false
	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			log.Debugf("list ", err.Error())
			return shim.Error(err.Error())
		}
		// Add a comma before array members, suppress it for the first array member
		if bArrayMemberAlreadyWritten == true {
			buffer.WriteString(",")
		}
		buffer.WriteString("{\"Key\":")
		buffer.WriteString("\"")
		buffer.WriteString(queryResponse.Key)
		buffer.WriteString("\"")

		buffer.WriteString(", \"Record\":")
		// Record is a JSON object, so we write as-is
		buffer.WriteString(string(queryResponse.Value))
		buffer.WriteString("}")
		bArrayMemberAlreadyWritten = true
	}
	buffer.WriteString("]")

	log.Infof("- listAllAcount:\n%s\n", buffer.String())

	return shim.Success(buffer.Bytes())
}

func (s *SmartContract) update(APIstub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 2 {
		log.Debugf("Incorrect number of arguments. Expecting 2")
		return shim.Error("Incorrect number of arguments. Expecting 2")
	}

	accountAsBytes, _ := APIstub.GetState(args[0])
	account := Account{}

	json.Unmarshal(accountAsBytes, &account)
	account.TransAmt = args[1]
	log.Debugf("Account update TransAmt:%s", args[1])
	accountAsBytes, _ = json.Marshal(account)
	APIstub.PutState(args[0], accountAsBytes)
	log.Debugf("Account update end")
	err := APIstub.SetEvent("update", accountAsBytes)
	if err != nil {
		log.Error("监听事件异常!", err)
	}
	log.Debugf("发送事件 %s", "update")

	return shim.Success(nil)
}

func (s *SmartContract) history(APIstub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		log.Debugf("Incorrect number of arguments. Expecting 2")
		return shim.Error("Incorrect number of arguments. Expecting 2")
	}

	resultsIterator, err := APIstub.GetHistoryForKey(args[0])
	if err != nil {
		log.Error("查询历史异常 %s %s", args[0], err.Error())
		return shim.Error(err.Error())
	}

	defer resultsIterator.Close()
	// buffer is a JSON array containing QueryRecords
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false
	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()
		if err != nil {
			log.Error("历史遍历异常 %s %s", queryResponse.TxId, err.Error())
			return shim.Error(err.Error())
		}
		// Add a comma before array members, suppress it for the first array member
		if bArrayMemberAlreadyWritten == true {
			buffer.WriteString(",")
		}
		item, _ := json.Marshal(queryResponse)
		buffer.Write(item)
		bArrayMemberAlreadyWritten = true
	}
	buffer.WriteString("]")
	log.Infof("historyResult:\n%s\n", buffer.String())
	return shim.Success(buffer.Bytes())

}
func (s *SmartContract) invoke(APIstub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) > 4 {
		log.Error("Incorrect number of arguments. Expecting > 4")
		return shim.Error("Incorrect number of arguments. Expecting 4")
	}

	var ccArgsArgs []byte
	for _, value := range args[3:] {
		ccArgsArgs = []byte(value)
	}
	ccArgs := [][]byte{[]byte(args[2]), ccArgsArgs}
	response := APIstub.InvokeChaincode(args[0], ccArgs, args[1])
	log.Infof("调用区块链 %s %s %s 返回:%s", args[0], args[1], ccArgs, response.Message)
	return shim.Success([]byte(response.Message))

}
func (s *SmartContract) check(APIstub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 2 {
		log.Error("Incorrect number of arguments. Expecting > 2")
		return shim.Error("Incorrect number of arguments. Expecting 2")
	}

	// businessid = args[0]
	Account, error := APIstub.GetState(args[0])

	if error != nil {
		log.Errorf("Can't find account info %s", args[0])
		return shim.Error("未发现对账信息")
	}
	jsonStr, _ := json.Marshal(Account)
	log.Infof("实现对账逻辑...%s", jsonStr)
	return shim.Success([]byte("对账完成"))
}

func main() {

	err := shim.Start(new(SmartContract))
	if err != nil {
		log.Errorf("Error creating new Smart Contract: %s", err)
	}
}
